package aop;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import dao.entity.UserDto;
import dao.hibernate.IGenericBaseCommonDao;
import dao.hibernate.MiniDaoConstants;
import dao.mybatis.IMybatisCommonDao;
import dao.mybatis.MybatisCommonDao;
import first.guodao.annotation.DaoType;
import first.guodao.annotation.Guodao;
import first.guodao.annotation.Methodtype;
import first.guodao.annotation.SQL;

public class MyMethodInterceptor implements MethodInterceptor {

	private IGenericBaseCommonDao miniDaoHiberCommonDao;
	private IMybatisCommonDao mybatisCommonDao;
	private JdbcTemplate jdbcTemplate;
	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

	/**
	 * @return the jdbcTemplate
	 */
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	/**
	 * @param jdbcTemplate
	 *            the jdbcTemplate to set
	 */
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	/**
	 * @return the mybatisCommonDao
	 */
	public IMybatisCommonDao getMybatisCommonDao() {
		return mybatisCommonDao;
	}

	/**
	 * @param mybatisCommonDao
	 *            the mybatisCommonDao to set
	 */
	public void setMybatisCommonDao(IMybatisCommonDao mybatisCommonDao) {
		this.mybatisCommonDao = mybatisCommonDao;
	}

	public Object invoke(MethodInvocation invocation) throws Throwable {
		Method method = invocation.getMethod();
		Object[] args = invocation.getArguments();
		Object returnObj = null;
		if (!Modifier.isAbstract(method.getModifiers())) {
			returnObj = invocation.proceed();
		}

		DaoType daotype = null;
		Methodtype methodtype = null;
		if (method.isAnnotationPresent(Methodtype.class)) {
			methodtype = method.getAnnotation(Methodtype.class);
			daotype = methodtype.value();
		}
		String methodname = methodtype.methodname();
		if (daotype.equals(DaoType.Hibernate)) {

			returnObj = miniDaoHiber(methodname, args);
		}
		if (daotype.equals(DaoType.Mybatis)) {
			String statement = method.getDeclaringClass() + "."
					+ method.getName();
			returnObj = DaoMybatis(methodname, args, statement.split(" ")[1]);
		} else if (daotype.equals(DaoType.Sql)) {
			String sql = method.getAnnotation(SQL.class).value();
			String returntype = method.getAnnotation(SQL.class).returntype();
			Class returntypeclass = Class.forName(returntype);
			List list = jdbcTemplateQuery(sql, returntypeclass);
			returnObj = list;
		}

		return returnObj;
	}

	/**
	 * @return the namedParameterJdbcTemplate
	 */
	public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
		return namedParameterJdbcTemplate;
	}

	/**
	 * @param namedParameterJdbcTemplate
	 *            the namedParameterJdbcTemplate to set
	 */
	public void setNamedParameterJdbcTemplate(
			NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
		this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
	}

	boolean isAbstract(Method method) {
		return Modifier.isAbstract(method.getModifiers());
	}

	/**
	 * MiniDao支持实体维护 说明：向下兼容Hibernate实体维护方式,实体的增删改查SQL自动生成,不需要写SQL
	 * 
	 * @param returnObj
	 * @param method
	 * @param args
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Object miniDaoHiber(String methodname, Object[] args) {

		if (MiniDaoConstants.METHOD_SAVE.equals(methodname)) {
			miniDaoHiberCommonDao.save(args[0]);
			return null;
		}
		if (MiniDaoConstants.METHOD_GET_BY_ID.equals(methodname)) {
			// 获取Dao方法与实体配置
			return miniDaoHiberCommonDao.get((Class) args[0],
					(Serializable) args[1]);
		}
		if (MiniDaoConstants.METHOD_GET_BY_ENTITY.equals(methodname)) {
			// 获取主键名
			return miniDaoHiberCommonDao.get(args[0]);
		}
		if (MiniDaoConstants.METHOD_UPDATE.equals(methodname)) {
			miniDaoHiberCommonDao.saveOrUpdate(args[0]);
			return null;
		}
		if (MiniDaoConstants.METHOD_DELETE.equals(methodname)) {
			miniDaoHiberCommonDao.delete(args[0]);
			return null;
		}
		if (MiniDaoConstants.METHOD_DELETE_BY_ID.equals(methodname)) {
			miniDaoHiberCommonDao.deleteEntityById((Class) args[0],
					(Serializable) args[1]);
			return null;
		}
		if (MiniDaoConstants.METHOD_LIST.equals(methodname)) {
			return miniDaoHiberCommonDao.loadAll(args[0]);
		}
		return null;
	}

	private Object DaoMybatis(String methodname, Object[] args, String statement) {

		if (MiniDaoConstants.METHOD_SAVE.equals(methodname)) {
			mybatisCommonDao.save(statement, args[0]);
			return null;
		}
		if (MiniDaoConstants.METHOD_SELECT.equals(methodname)) {
			// 获取Dao方法与实体配置
			return mybatisCommonDao.selectlist(statement, args);
		}
		if (MiniDaoConstants.METHOD_GET_BY_ID.equals(methodname)) {
			// 获取Dao方法与实体配置
			return mybatisCommonDao.findbyId(statement, (Serializable) args[1]);
		}
		if (MiniDaoConstants.METHOD_GET_BY_ENTITY.equals(methodname)) {
			// 获取Dao方法与实体配置
			return mybatisCommonDao.getByEntity(statement, args[0]);
		}
		if (MiniDaoConstants.METHOD_UPDATE.equals(methodname)) {
			mybatisCommonDao.update(statement, args[0]);
			return null;
		}
		if (MiniDaoConstants.METHOD_DELETE.equals(methodname)) {
			mybatisCommonDao.delete(statement, args[0]);
			return null;
		}
		if (MiniDaoConstants.METHOD_DELETE_BY_ID.equals(methodname)) {
			mybatisCommonDao.delete(statement, (Serializable) args[1]);
			return null;
		}
		return null;
	}

	public List jdbcTemplateQuery(String sql, Class returntype) {
		List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
		List res = new ArrayList();
		for (int i = 0; i < list.size(); i++) {
			Map<String, Object> map = list.get(i);
			res.add(convertMap(returntype, map));
		}
		return res;
	}

	public List NamejdbcTemplateQuery(String sql, Map paramMap, Class returntype) {
		List list = namedParameterJdbcTemplate.queryForList(sql, paramMap,
				returntype);
		/*
		 * List res = new ArrayList(); for (int i = 0; i < list.size(); i++) {
		 * Map<String, Object> map = list.get(i); res.add(convertMap(returntype,
		 * map)); } return res;
		 */
		return null;
	}

	/**
	 * @return the miniDaoHiberCommonDao
	 */
	public IGenericBaseCommonDao getMiniDaoHiberCommonDao() {
		return miniDaoHiberCommonDao;
	}

	/**
	 * @param miniDaoHiberCommonDao
	 *            the miniDaoHiberCommonDao to set
	 */
	public void setMiniDaoHiberCommonDao(
			IGenericBaseCommonDao miniDaoHiberCommonDao) {
		this.miniDaoHiberCommonDao = miniDaoHiberCommonDao;
	}

	public static Object convertMap(Class type, Map<String, Object> map) {
		Object obj = null;
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(type);
			obj = type.newInstance(); // 创建
			// 给 JavaBean 对象的属性赋值
			PropertyDescriptor[] propertyDescriptors = beanInfo
					.getPropertyDescriptors();
			for (int i = 0; i < propertyDescriptors.length; i++) {
				PropertyDescriptor descriptor = propertyDescriptors[i];
				String propertyName = descriptor.getName();

				if (map.containsKey(propertyName)) {
					// 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
					Object value = map.get(propertyName);

					Object[] args = new Object[1];
					args[0] = value;
					Class valueClass = value.getClass();
					if (!valueClass.equals(descriptor.getPropertyType())) {
						if (valueClass.equals(java.math.BigDecimal.class)) {
							if (descriptor.getPropertyType().equals(
									java.lang.Integer.class)) {
								args[0] = ((java.math.BigDecimal) value)
										.intValue();
							} else if (descriptor.getPropertyType().equals(
									java.lang.Long.class)) {
								args[0] = ((java.math.BigDecimal) value)
										.longValue();
							} else if (descriptor.getPropertyType().equals(
									java.lang.Double.class)) {
								args[0] = ((java.math.BigDecimal) value)
										.doubleValue();
							}
						} else {
							args[0] = null;
						}
					}
					descriptor.getWriteMethod().invoke(obj, args);
				}
			}
		} catch (IntrospectionException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {

			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}

		// 给 JavaBean 对象的属性赋值

		return obj;
	}
}
